package com.winning.gjhlht.ihe.job.jober;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Timer;

import javax.swing.text.AbstractDocument.Content;

import org.apache.log4j.Logger;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import com.winning.common.Constans;
import com.winning.common.beans.ihe.IHERequestBodyBean;
import com.winning.common.beans.ihe.IHERequestItemBean;
import com.winning.common.beans.xmlTemp.XMLTempConfigBean;
import com.winning.common.data.service.PlatBasicDataService;
import com.winning.common.tools.SQLTool;
import com.winning.common.tools.XMLTool;
import com.winning.core.job.BaseJob;
import com.winning.gjhlht.ihe.cdaService.controller.CDAController;
import com.winning.gjhlht.ihe.job.thread.IHERegistrationRequestTask;

/**
 * 类名称：ResidentInfoUploadJob
 * 类描述：IHE数据上传任务通用执行器
 * 创建人：liuwensheng
 * 创建时间：2016-12-8 下午5:14:13
 * 修改人：liuwensheng
 * 修改时间：2016-12-8 下午5:14:13
 * 修改备注：
 */
public class IHERegistrationRequestJober extends BaseJob {
    private static Logger LOGGER = Logger.getLogger(Constans.LOG4J_PBS_LOGGER_ID);

    private PlatBasicDataService platBasicDataService = null;

    /**
     * 作业执行器定时自动执行
     */
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {


        JobDataMap jobDataMap = getJobDataMap(context);

        //后去平台基础数据服务对象
        platBasicDataService = (PlatBasicDataService) jobDataMap.get(PLAT_BASIC_DATA_SERVICE);

        //一个模板bean，主要包含该接口的模板文件地址、任务执行时间
        XMLTempConfigBean xmlTempConfigBean = (XMLTempConfigBean) jobDataMap.get(XML_TEMP_CONFIG_BEAN);

        //xml配置模板的地址
        String tempFilePath = xmlTempConfigBean.getXmlTempFilePath();

        //初始化过程中，解析模板配置信息,每次任务启动时，执行, 模板配置文件中包含：消息XML的文件地址和具体节点的关联参数
        IHERequestBodyBean iheRequestBodyBean = getIHERequestBodyBeanHandler(tempFilePath);

        //配置的IHE请求消息xml文件地址, 目标XML结构文件
        String iheMessageFilePath = iheRequestBodyBean.getRequestMessageFilePath();

        //获取IHE请求消息XML可操作对象
        Document document = XMLTool.getXMLDocument(iheMessageFilePath);

        //转成XML字符串
        String xmlStr = document.asXML() == null ? "" : document.asXML();

        //去除XML头部信息
        xmlStr = xmlStr.substring(39, xmlStr.length());

        //2、多批次：从数据库中获取业务数据，需要增加对增量更新流程的处理和分页上传处理
        pluralPCOperateDataHandler(xmlTempConfigBean, document, iheRequestBodyBean);
    }

    /**
     * 多批次执行
     * 由于一次全部查询所有结果集太大，可采用分页原理，分批次从数据库中抽取数据，在分线程上传数据 <br/>
     * 方法名称: pluralPCOperateDataHandler
     *
     * @param
     * @return void  返回类型说明<br/>
     * @throws <br/>
     * @author liuwensheng@winning.com.cn<br/>
     * 创建时间：2016-12-13/下午4:30:00<br/>
     */
    private void pluralPCOperateDataHandler(XMLTempConfigBean xmlTempConfigBean, Document documentSource, IHERequestBodyBean iheRequestBodyBean) {
        String serviceID = xmlTempConfigBean.getServiceID();

        String serviceName = xmlTempConfigBean.getServiceName();

        String basicSQL = iheRequestBodyBean.getSqlValue();

        //1、从基础SQL中按照规则提取增量更新表名称，规则为TABLENAME_TBRQ，TBRQ是平台所有表必须有的字段
        HashMap<String, String> tableNameMap = SQLTool.getTableNameFromSQL(basicSQL);

        //2、获取业务库中保存的增量更新时间
        HashMap<String, String> tableValueMapFromDB = platBasicDataService.getTableIncreaseTimeMapFromDB();

        //3、增加增量流程的SQL
        String increaseSQLStr = SQLTool.createIncreaseSQL(serviceID, basicSQL, tableNameMap, tableValueMapFromDB);

        LOGGER.info("--> Service ID:" + serviceName + "; 基础配置SQL为:[" + basicSQL + "]");

        LOGGER.info("--> Service ID:" + serviceName + "; 增量更新处理后SQL为:[" + increaseSQLStr + "]");

        //4、统计SQL
        String countSQL = "SELECT " + "COUNT(1) AS " + BaseJob.COLUMN_COUNT + " FROM (" + increaseSQLStr + ") A";


        LOGGER.info("--> Service ID:" + serviceName + "; 查询总数SQL为:[" + countSQL + "]");

        //总共查询出多少条数据量, 多数据源支持
        int totalDataCount = platBasicDataService.getPlatBasicDataCountHandler(countSQL, BaseJob.COLUMN_COUNT, xmlTempConfigBean.getDbDataSourseID());

        LOGGER.info("--> Service ID:" + serviceName + "; 总数据量为:[" + totalDataCount + "]");

        //【2】、计算需要创建的线程数量
        int jobsNumber = 1;

        //一批次上传的数据量，也可理解为一页的数量
        int perSize = 100;


        jobsNumber = totalDataCount / perSize;

        if (totalDataCount % perSize > 0) {
            jobsNumber += 1;
        }

        //批次分页页码
        int pageIndexNum = 0;

        //分批次执行上传
        for (int pcStartIndex = 0; pcStartIndex < jobsNumber; pcStartIndex++) {
            //每次都会在sql中增加最新的增量时间，每次都应该是从第一页开始
            List<Map<String, Object>> registrationRequestInfoDataList = platBasicDataService.getPlatBasicDataByIncreaseTimeHandler(xmlTempConfigBean.getDbDataSourseID(), serviceID, basicSQL, pageIndexNum, perSize);


            if (registrationRequestInfoDataList == null || registrationRequestInfoDataList.size() == 0) {
                LOGGER.info("没有数据");
            } else {
                int result = createIHERegistrationRequestTaskHandler(xmlTempConfigBean, documentSource, registrationRequestInfoDataList, iheRequestBodyBean);

                if (result > 0) {
                    /* 返回1，是因为，业务发生时间和数据库记录的增量时间相同，表示一个时间段内发生的数据量太大（同一时间内的数据量远大于一页）
                     * 第二批次查询数据就必须向后翻一页。
                     */
                    pageIndexNum += 1;
                } else {
                    //返回0，是因为，SQL每次都会做增量时间操作，每次的查询都是根据最新的时间筛选，所以每次的查询结果集都应该是从第一页开始。
                    pageIndexNum = 0;
                }
            }


        }
    }

    /**
     * 创建IHE患者信息注册XML <br/>
     * 方法名称: createIHERegistrationRequestXMLHandler
     *
     * @param
     * @return void  返回类型说明<br/>
     * @throws <br/>
     * @author liuwensheng@winning.com.cn<br/>
     * 创建时间：2016-12-10/上午11:36:43<br/>
     */
    private int createIHERegistrationRequestTaskHandler(XMLTempConfigBean xmlTempConfigBean, Document documentSource, List<Map<String, Object>> registrationRequestInfoDataList, IHERequestBodyBean iheRequestBodyBean) {
        String serviceID = xmlTempConfigBean.getServiceID();

        String serviceName = xmlTempConfigBean.getServiceName();

        //单个线程可执行的上传数据量
        int baseNumber = 10;

        //计算处理所有数据需要启动的线程数量
        int totalNumber = registrationRequestInfoDataList.size();
        int threadNumber = totalNumber / baseNumber;

        if (totalNumber % baseNumber > 0) {
            threadNumber += 1;
        }

        List<IHERegistrationRequestTask> dataSetSubmitThreadList = new ArrayList<IHERegistrationRequestTask>();

        //创建提交数据线程
        for (int j = 0; j < threadNumber; j++) {
            int fromIndex = j * baseNumber;
            int toIndex = (j + 1) * baseNumber;

            List<Map<String, Object>> tempRowListValue = new ArrayList<Map<String, Object>>();

            //截取一段数据
            for (int index = fromIndex; index < toIndex; index++) {
                if (index < registrationRequestInfoDataList.size()) {
                    tempRowListValue.add(registrationRequestInfoDataList.get(index));
                }
            }

            Timer timer = new Timer();

            //创建执行上传数据接口的线程
            IHERegistrationRequestTask dataSetSubmitThread = new IHERegistrationRequestTask(documentSource, tempRowListValue, iheRequestBodyBean, platBasicDataService, xmlTempConfigBean);
            timer.schedule(dataSetSubmitThread, 0);

            //保存所有的线程
            dataSetSubmitThreadList.add(dataSetSubmitThread);
        }

        //********************* 2、检查所有子线程的执行结果，一批提交接口线程数据执行结果 *********************
        boolean isAllOver = false;

        //当前线程已经变换为监控线程，持续判断子线程的执行结果，如果所有子线程全部执行完毕，表示当前job执行结束。可做更新增量时间操作
        while (!isAllOver) {
            for (int threadIndex = 0; dataSetSubmitThreadList != null && threadIndex < dataSetSubmitThreadList.size(); threadIndex++) {
                IHERegistrationRequestTask iheRegistrationRequestTask = dataSetSubmitThreadList.get(threadIndex);

                if (!iheRegistrationRequestTask.isOver()) {
                    isAllOver = false;
                    break;
                }

                iheRegistrationRequestTask.cancel();
                iheRegistrationRequestTask = null;

                isAllOver = true;

            }

            try {
                //持续监控
                Thread.sleep(10);
            } catch (InterruptedException e) {
                //打印异常堆栈信息
                LOGGER.error(e, e.fillInStackTrace());
                e.printStackTrace();
            }
        }

        //********************* 3、所有线程执行完毕后，更新增量时间 *********************
        String basicSQL = iheRequestBodyBean.getSqlValue();
        LOGGER.info("-->开始更新增量更新时间");
        int pageIndexNum = platBasicDataService.saveMaxTBRQToDB("xj", serviceID, serviceName, basicSQL, xmlTempConfigBean.getDbDataSourseID());
        LOGGER.info("-->增量更新时间更新结束");


        return pageIndexNum;
    }

    /**
     * 获取配置模板信息 <br/>
     * 方法名称: getIHERequestBodyBeanHandler
     *
     * @param
     * @return IHERequestBodyBean  返回类型说明<br/>
     * @throws <br/>
     * @author liuwensheng@winning.com.cn<br/>
     * 创建时间：2016-12-13/上午11:20:51<br/>
     */
    private IHERequestBodyBean getIHERequestBodyBeanHandler(String xmFilelTempPath) {
        Document document = XMLTool.getXMLDocument(xmFilelTempPath);

        //IHE请求消息模板实体对象
        IHERequestBodyBean iheRequestBodyBean = new IHERequestBodyBean();

        if (document != null) {
            Element rootElment = document.getRootElement();
            Element requestBodyElment = rootElment.element(Constans.REQUEST_BODY_ATTRIBUTE);

            //对应请求消息XML文件地址
            Attribute requestMessageFilePathAttr = requestBodyElment.attribute(Constans.REQUEST_MESSAGE_FILE_PATH_ATTRIBUTE);
            if (requestMessageFilePathAttr != null) {
                String requestMessageFilePathValue = requestMessageFilePathAttr.getStringValue();
                iheRequestBodyBean.setRequestMessageFilePath(requestMessageFilePathValue);
            }

            //查询业务数据的sql
            Attribute sqlValueAttr = requestBodyElment.attribute(Constans.SQL_VALUE_ATTRIBUTE);
            if (sqlValueAttr != null) {
                String sqlValue = sqlValueAttr.getStringValue();
                iheRequestBodyBean.setSqlValue(sqlValue);
            }

            //webservice开发的接口方法名称
            Attribute webserviceMethodNameAttr = requestBodyElment.attribute(Constans.WEBSERVICE_METHOD_NAME_ATTRIBUTE);
            if (webserviceMethodNameAttr != null) {
                String webserviceMethodNameValue = webserviceMethodNameAttr.getStringValue();
                iheRequestBodyBean.setWebserviceMethodName(webserviceMethodNameValue);
            }

            //webservcie服务地址，指向到具体的wsdl
            Attribute webserviceURLAttr = requestBodyElment.attribute(Constans.WEBSERVICE_URL_ATTRIBUTE);
            if (webserviceURLAttr != null) {
                String webserviceURLValue = webserviceURLAttr.getStringValue();
                iheRequestBodyBean.setWebserviceURL(webserviceURLValue);
            }

            //是否调用审计接口，共享文档注册需要调用
            Attribute isAuditAttr = requestBodyElment.attribute(Constans.IS_AUDIT_ATTRIBUTE);
            if (isAuditAttr != null) {
                String isAuditValue = isAuditAttr.getStringValue();

                if ("true".equals(isAuditValue)) {
                    iheRequestBodyBean.setAudit(true);
                } else {
                    iheRequestBodyBean.setAudit(false);
                }
            }

            //审计接口webservcie服务地址，指向到具体的wsdl
            Attribute auditWebserviceURLAttr = requestBodyElment.attribute(Constans.AUDIT_WEBSERVICE_URL_ATTRIBUTE);
            if (auditWebserviceURLAttr != null) {
                String auditWebserviceURLValue = auditWebserviceURLAttr.getStringValue();
                iheRequestBodyBean.setAuditWebserviceURL(auditWebserviceURLValue);
            }

            //平台webservice接口服务名称
            Attribute actionMethodNameAttr = requestBodyElment.attribute(Constans.ACTION_METHOD_NAME_ATTRIBUTE);
            if (actionMethodNameAttr != null) {
                String actionMethodNameValue = actionMethodNameAttr.getStringValue();
                iheRequestBodyBean.setActionMethodName(actionMethodNameValue);
            }

            //IHE消息响应结果处理class
            Attribute responseClassAttr = requestBodyElment.attribute(Constans.RESPONSE_CLASS_ATTRIBUTE);
            if (responseClassAttr != null) {
                String responseClassValue = responseClassAttr.getStringValue();
                iheRequestBodyBean.setResponseClass(responseClassValue);
            }

            //明细列表
            List<IHERequestItemBean> iheRequestItemList = new ArrayList<IHERequestItemBean>();

            //获取详情列表
            for (Iterator<Element> iterator = requestBodyElment.elementIterator(); iterator.hasNext(); ) {
                IHERequestItemBean iheRequestItemBean = new IHERequestItemBean();

                Element childElement = iterator.next();

                Attribute xPathValueAttr = childElement.attribute(Constans.X_PATH_VALUE_ATTRIBUTE);
                if (xPathValueAttr != null) {
                    String xPathValue = xPathValueAttr.getStringValue();
                    iheRequestItemBean.setxPathValue(xPathValue);
                }

                // xpath指向的xml结构的类型,大小写不区分，统一为大写
                Attribute xPathTypeAttr = childElement.attribute(Constans.X_PATH_TYPE_ATTRIBUTE);
                if (xPathTypeAttr != null) {
                    String xPathType = xPathTypeAttr.getStringValue() == null ? "" : xPathTypeAttr.getStringValue().toUpperCase();
                    if (Constans.XML_ELEMENT_TYPE.equals(xPathType)) {
                        iheRequestItemBean.setxPathType(Constans.XML_ELEMENT_TYPE);
                    } else {
                        iheRequestItemBean.setxPathType(Constans.XML_ATTRIBUTE_TYPE);
                    }
                }

                Attribute localColumnNameAttr = childElement.attribute(Constans.LOCAL_COLUMN_NAME_ATTRIBUTE);
                if (localColumnNameAttr != null) {
                    String localColumnName = localColumnNameAttr.getStringValue() == null ? "" : localColumnNameAttr.getStringValue().toUpperCase();
                    iheRequestItemBean.setLocalColumnName(localColumnName);
                }

                //默认值
                Attribute defaultValueAttr = childElement.attribute(Constans.DEFAULT_VALUE_ATTRIBUTE);
                if (defaultValueAttr != null) {
                    String defaultValue = defaultValueAttr.getStringValue() == null ? "" : defaultValueAttr.getStringValue().toUpperCase();
                    iheRequestItemBean.setDefaultValue(defaultValue);
                }

                //数据类型,大小写不区分, 统一为大写
                Attribute dataTypeAttr = childElement.attribute(Constans.DATA_TYPE_ATTRIBUTE);
                if (dataTypeAttr != null) {
                    String dataType = dataTypeAttr.getStringValue() == null ? "" : dataTypeAttr.getStringValue().toUpperCase();
                    if (Constans.DATE_TYPE.equals(dataType)) {
                        iheRequestItemBean.setDataType(Constans.DATE_TYPE);
                    } else if (Constans.GUID_TYPE.equals(dataType)) {
                        iheRequestItemBean.setDataType(Constans.GUID_TYPE);
                    } else if (Constans.CLOB_TYPE.equals(dataType)) {
                        iheRequestItemBean.setDataType(Constans.CLOB_TYPE);
                    } else if (Constans.XML_TYPE.equals(dataType)) {
                        iheRequestItemBean.setDataType(Constans.XML_TYPE);
                    } else {
                        iheRequestItemBean.setDataType(Constans.STRING_TYPE);
                    }
                }

                //大小写区分
                Attribute dataFormatterAttr = childElement.attribute(Constans.DATA_FORMATTER_ATTRIBUTE);
                if (dataFormatterAttr != null) {
                    String dataFormatter = dataFormatterAttr.getStringValue();
                    iheRequestItemBean.setDataFormatter(dataFormatter);
                }

                iheRequestItemList.add(iheRequestItemBean);
            }

            //保存所有配置明细列表
            iheRequestBodyBean.setIheRequestItemList(iheRequestItemList);
        }

        return iheRequestBodyBean;
    }

    /**
     * 删除临时CDA文件
     * 方法名称: deleteTempCDAFile
     *
     * @param
     * @return void  返回类型说明<br/>
     * @throws <br/>
     * @author lenovo@winning.com.cn<br/>
     * 创建时间：2017-1-19/上午12:16:57<br/>
     */
    public void deleteTempCDAFile() {

        LOGGER.info("-->开始删除临时CDA文件的内容");

        String filePath = "E:/thirdParty/cda";

        File temp = null;
        try {
            File file = new File(filePath);

            if (file.exists() && file.isDirectory()) {

                String[] tempList = file.list();

                if (tempList != null) {
                    for (int i = 0; i < tempList.length; i++) {
                        temp = new File(filePath + "/" + tempList[i]);


                        if (file.exists()) {
                            if (temp.isFile()) {
                                temp.delete();
                            }
                        }

                    }
                }
            }


        } catch (Exception e) {
            LOGGER.error(e, e.fillInStackTrace());
        }
    }
}
